//
// Created by 33145 on 2023/5/27.
//

#ifndef TINYTINYRPC_LOG_H
#define TINYTINYRPC_LOG_H
#ifndef ROCKET_COMMON_LOG_H
#define ROCKET_COMMON_LOG_H

#include <string>
#include <queue>
#include <memory>
#include <semaphore.h>

#include "rocket/common/config.h"
#include "rocket/common/mutex.h"
#include "rocket/net/timer_event.h"

namespace rocket {


  template<typename... Args>
  std::string formatString(const char* str, Args&&... args) {

    int size = snprintf(nullptr, 0, str, args...);

    std::string result;
    if (size > 0) {
      result.resize(size);
      snprintf(&result[0], size + 1, str, args...);
    }

    return result;
  }


#define LOG_DEBUG(str, ...) \
  if (rocket::Logger::GetGlobalLogger()->getLogLevel() && rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Debug) \
  { \
    rocket::Logger::GetGlobalLogger()->pushLog(rocket::LogEvent(rocket::LogLevel::Debug).toString() \
      + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\
  } \


#define LOG_INFO(str, ...) \
  if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Info) \
  { \
    rocket::Logger::GetGlobalLogger()->pushLog(rocket::LogEvent(rocket::LogLevel::Info).toString() \
    + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\
  } \

#define LOG_ERROR(str, ...) \
  if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Error) \
  { \
    rocket::Logger::GetGlobalLogger()->pushLog(rocket::LogEvent(rocket::LogLevel::Error).toString() \
      + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\
  } \


#define LOG_APPDEBUG(str, ...) \
  if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Debug) \
  { \
    rocket::Logger::GetGlobalLogger()->pushAppLog(rocket::LogEvent(rocket::LogLevel::Debug).toString() \
      + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\
  } \


#define LOG_APPINFO(str, ...) \
  if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Info) \
  { \
    rocket::Logger::GetGlobalLogger()->pushAppLog(rocket::LogEvent(rocket::LogLevel::Info).toString() \
    + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\
  } \

#define LOG_APPERROR(str, ...) \
  if (rocket::Logger::GetGlobalLogger()->getLogLevel() <= rocket::Error) \
  { \
    rocket::Logger::GetGlobalLogger()->pushAppLog(rocket::LogEvent(rocket::LogLevel::Error).toString() \
      + "[" + std::string(__FILE__) + ":" + std::to_string(__LINE__) + "]\t" + rocket::formatString(str, ##__VA_ARGS__) + "\n");\
  } \



  enum LogLevel {
    Unknown = 0,
    Debug = 1,
    Info = 2,
    Error = 3
  };


  std::string LogLevelToString(LogLevel level);

  LogLevel StringToLogLevel(const std::string& log_level);

  class AsyncLogger {

  public:
    typedef std::shared_ptr<AsyncLogger> s_ptr;
    AsyncLogger(const std::string& file_name, const std::string& file_path, int max_size);

    void stop();

    // 刷新到磁盘
    void flush();

    void pushLogBuffer(std::vector<std::string>& vec);


  public:
    static void* Loop(void*);

  public:
    pthread_t _thread;

  private:
    // _file_path/_file_name_yyyymmdd.0

    std::queue<std::vector<std::string>> _buffer;

    std::string _file_name;    // 日志输出文件名字
    std::string _file_path;    // 日志输出路径
    int _max_file_size {0};    // 日志单个文件最大大小, 单位为字节

    sem_t _sempahore;

    pthread_cond_t _condtion;  // 条件变量
    Mutex _mutex;

    std::string _date;   // 当前打印日志的文件日期
    FILE* _file_hanlder {NULL};   // 当前打开的日志文件句柄

    bool _reopen_flag {false};

    int _no {0};   // 日志文件序号

    bool _stop_flag {false};

  };

  class Logger {
  public:
    typedef std::shared_ptr<Logger> s_ptr;

    Logger(LogLevel level, int type = 1);

    void pushLog(const std::string& msg);

    void pushAppLog(const std::string& msg);

    void init();

    void log();

    LogLevel getLogLevel() const {
      return _set_level;
    }

    AsyncLogger::s_ptr getAsyncAppLopger() {
      return _asnyc_app_logger;
    }

    AsyncLogger::s_ptr getAsyncLopger() {
      return _asnyc_logger;
    }

    void syncLoop();

    void flush();

  public:
    static Logger* GetGlobalLogger();

    static void InitGlobalLogger(int type = 1);

  private:
    LogLevel _set_level;
    std::vector<std::string> _buffer;

    std::vector<std::string> _app_buffer;

    Mutex _mutex;

    Mutex _app_mutex;

    // _file_path/_file_name_yyyymmdd.1

    std::string _file_name;    // 日志输出文件名字
    std::string _file_path;    // 日志输出路径
    int _max_file_size {0};    // 日志单个文件最大大小

    AsyncLogger::s_ptr _asnyc_logger;

    AsyncLogger::s_ptr _asnyc_app_logger;

    TimerEvent::ptr _timer_event;

    int _type {0};

  };


  class LogEvent {
  public:

    LogEvent(LogLevel level) : _level(level) {}

    std::string getFileName() const {
      return _file_name;
    }

    LogLevel getLogLevel() const {
      return _level;
    }

    std::string toString();


  private:
    std::string _file_name;  // 文件名
    int32_t _file_line;  // 行号
    int32_t _pid;  // 进程号
    int32_t _thread_id;  // 线程号

    LogLevel _level;     //日志级别

  };



}

#endif
#endif //TINYTINYRPC_LOG_H
